<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <meta
      name="description"
      content="Layer imagery from multiple sources, including WMS servers, Bing Maps, ArcGIS Online, OpenStreetMaps, and more, and adjust the alpha of each independently."
    />
    <meta name="cesium-sandcastle-labels" content="Showcases" />
    <title>Cesium Demo</title>
    <script type="text/javascript" src="../Sandcastle-header.js"></script>
    <script
      type="text/javascript"
      src="../../../Build/CesiumUnminified/Cesium.js"
      nomodule
    ></script>
    <script type="module" src="../load-cesium-es6.js"></script>
  </head>
  <body
    class="sandcastle-loading"
    data-sandcastle-bucket="bucket-requirejs.html"
  >
    <style>
      @import url(../templates/bucket.css);

      #toolbar {
        background: rgba(42, 42, 42, 0.8);
        padding: 4px;
        border-radius: 4px;
      }

      #toolbar input {
        vertical-align: middle;
        padding-top: 2px;
        padding-bottom: 2px;
      }

      #toolbar table tr {
        transform: translateY(0);
        transition: transform 0.4s ease-out;
      }

      #toolbar table tr.up {
        transform: translateY(33px);
        transition: none;
      }

      #toolbar table tr.down {
        transform: translateY(-33px);
        transition: none;
      }
    </style>
    <div id="cesiumContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar">
      <table>
        <tbody data-bind="foreach: layers">
          <tr
            data-bind="css: { up: $parent.upLayer === $data, down: $parent.downLayer === $data }"
          >
            <td><input type="checkbox" data-bind="checked: show" /></td>
            <td>
              <span
                data-bind="text: name, visible: !$parent.isSelectableLayer($data)"
              ></span>
              <select
                data-bind="visible: $parent.isSelectableLayer($data), options: $parent.baseLayers, optionsText: 'name', value: $parent.selectedLayer"
              ></select>
            </td>
            <td>
              <input
                type="range"
                min="0"
                max="1"
                step="0.01"
                data-bind="value: alpha, valueUpdate: 'input'"
              />
            </td>
            <td>
              <button
                type="button"
                class="cesium-button"
                data-bind="click: function() { $parent.raise($data, $index()); }, visible: $parent.canRaise($index())"
              >
                ▲
              </button>
            </td>
            <td>
              <button
                type="button"
                class="cesium-button"
                data-bind="click: function() { $parent.lower($data, $index()); }, visible: $parent.canLower($index())"
              >
                ▼
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <script id="cesium_sandcastle_script">
      function startup(Cesium) {
        "use strict";
        //Sandcastle_Begin
        const viewer = new Cesium.Viewer("cesiumContainer", {
          baseLayerPicker: false,
        });
        const imageryLayers = viewer.imageryLayers;

        const viewModel = {
          layers: [],
          baseLayers: [],
          upLayer: null,
          downLayer: null,
          selectedLayer: null,
          isSelectableLayer: function (layer) {
            return this.baseLayers.indexOf(layer) >= 0;
          },
          raise: function (layer, index) {
            imageryLayers.raise(layer);
            viewModel.upLayer = layer;
            viewModel.downLayer = viewModel.layers[Math.max(0, index - 1)];
            updateLayerList();
            window.setTimeout(function () {
              viewModel.upLayer = viewModel.downLayer = null;
            }, 10);
          },
          lower: function (layer, index) {
            imageryLayers.lower(layer);
            viewModel.upLayer =
              viewModel.layers[
                Math.min(viewModel.layers.length - 1, index + 1)
              ];
            viewModel.downLayer = layer;
            updateLayerList();
            window.setTimeout(function () {
              viewModel.upLayer = viewModel.downLayer = null;
            }, 10);
          },
          canRaise: function (layerIndex) {
            return layerIndex > 0;
          },
          canLower: function (layerIndex) {
            return layerIndex >= 0 && layerIndex < imageryLayers.length - 1;
          },
        };
        const baseLayers = viewModel.baseLayers;

        Cesium.knockout.track(viewModel);

        function setupLayers() {
          // Create all the base layers that this example will support.
          // These base layers aren't really special.  It's possible to have multiple of them
          // enabled at once, just like the other layers, but it doesn't make much sense because
          // all of these layers cover the entire globe and are opaque.
          addBaseLayerOption("Bing Maps Aerial", undefined); // the current base layer
          addBaseLayerOption(
            "Bing Maps Road",
            Cesium.createWorldImagery({
              style: Cesium.IonWorldImageryStyle.ROAD,
            })
          );
          addBaseLayerOption(
            "ArcGIS World Street Maps",
            new Cesium.ArcGisMapServerImageryProvider({
              url:
                "https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",
            })
          );
          addBaseLayerOption(
            "OpenStreetMaps",
            new Cesium.OpenStreetMapImageryProvider()
          );
          addBaseLayerOption(
            "Stamen Maps",
            new Cesium.OpenStreetMapImageryProvider({
              url: "https://stamen-tiles.a.ssl.fastly.net/watercolor/",
              fileExtension: "jpg",
              credit:
                "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.",
            })
          );
          addBaseLayerOption(
            "Natural Earth II (local)",
            new Cesium.TileMapServiceImageryProvider({
              url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
            })
          );
          addBaseLayerOption(
            "USGS Shaded Relief (via WMTS)",
            new Cesium.WebMapTileServiceImageryProvider({
              url:
                "https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS",
              layer: "USGSShadedReliefOnly",
              style: "default",
              format: "image/jpeg",
              tileMatrixSetID: "default028mm",
              maximumLevel: 19,
              credit: "U. S. Geological Survey",
            })
          );

          // Create the additional layers
          addAdditionalLayerOption(
            "United States GOES Infrared",
            new Cesium.WebMapServiceImageryProvider({
              url:
                "https://mesonet.agron.iastate.edu/cgi-bin/wms/goes/conus_ir.cgi?",
              layers: "goes_conus_ir",
              credit: "Infrared data courtesy Iowa Environmental Mesonet",
              parameters: {
                transparent: "true",
                format: "image/png",
              },
            })
          );
          addAdditionalLayerOption(
            "United States Weather Radar",
            new Cesium.WebMapServiceImageryProvider({
              url:
                "https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi?",
              layers: "nexrad-n0r",
              credit: "Radar data courtesy Iowa Environmental Mesonet",
              parameters: {
                transparent: "true",
                format: "image/png",
              },
            })
          );
          addAdditionalLayerOption(
            "TileMapService Image",
            new Cesium.TileMapServiceImageryProvider({
              url: "../images/cesium_maptiler/Cesium_Logo_Color",
            }),
            0.2
          );
          addAdditionalLayerOption(
            "Single Image",
            new Cesium.SingleTileImageryProvider({
              url: "../images/Cesium_Logo_overlay.png",
              rectangle: Cesium.Rectangle.fromDegrees(
                -115.0,
                38.0,
                -107,
                39.75
              ),
            }),
            1.0
          );
          addAdditionalLayerOption(
            "Grid",
            new Cesium.GridImageryProvider(),
            1.0,
            false
          );
          addAdditionalLayerOption(
            "Tile Coordinates",
            new Cesium.TileCoordinatesImageryProvider(),
            1.0,
            false
          );
        }

        function addBaseLayerOption(name, imageryProvider) {
          let layer;
          if (typeof imageryProvider === "undefined") {
            layer = imageryLayers.get(0);
            viewModel.selectedLayer = layer;
          } else {
            layer = new Cesium.ImageryLayer(imageryProvider);
          }

          layer.name = name;
          baseLayers.push(layer);
        }

        function addAdditionalLayerOption(name, imageryProvider, alpha, show) {
          const layer = imageryLayers.addImageryProvider(imageryProvider);
          layer.alpha = Cesium.defaultValue(alpha, 0.5);
          layer.show = Cesium.defaultValue(show, true);
          layer.name = name;
          Cesium.knockout.track(layer, ["alpha", "show", "name"]);
        }

        function updateLayerList() {
          const numLayers = imageryLayers.length;
          viewModel.layers.splice(0, viewModel.layers.length);
          for (let i = numLayers - 1; i >= 0; --i) {
            viewModel.layers.push(imageryLayers.get(i));
          }
        }

        setupLayers();
        updateLayerList();

        //Bind the viewModel to the DOM elements of the UI that call for it.
        const toolbar = document.getElementById("toolbar");
        Cesium.knockout.applyBindings(viewModel, toolbar);

        Cesium.knockout
          .getObservable(viewModel, "selectedLayer")
          .subscribe(function (baseLayer) {
            // Handle changes to the drop-down base layer selector.
            let activeLayerIndex = 0;
            const numLayers = viewModel.layers.length;
            for (let i = 0; i < numLayers; ++i) {
              if (viewModel.isSelectableLayer(viewModel.layers[i])) {
                activeLayerIndex = i;
                break;
              }
            }
            const activeLayer = viewModel.layers[activeLayerIndex];
            const show = activeLayer.show;
            const alpha = activeLayer.alpha;
            imageryLayers.remove(activeLayer, false);
            imageryLayers.add(baseLayer, numLayers - activeLayerIndex - 1);
            baseLayer.show = show;
            baseLayer.alpha = alpha;
            updateLayerList();
          });

        //Sandcastle_End
        Sandcastle.finishedLoading();
      }
      if (typeof Cesium !== "undefined") {
        window.startupCalled = true;
        startup(Cesium);
      }
    </script>
  </body>
</html>
